﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using IntelligentDecisioning.SharePoint.Definition;
using IntelligentDecisioning.SharePoint.Logging;
using IntelligentDecisioning.SharePoint.Definition.Fields;

namespace IntelligentDecisioning.SharePoint.Helpers
{
    public class IDContentTypeHelper: IDSharePointHelper
    {
        #region Constructor

        public IDContentTypeHelper(SPSite siteCollection, SPWeb targetWeb)
            : base(siteCollection, targetWeb, new NoLog())
        {

        }

        public IDContentTypeHelper(SPSite siteCollection, SPWeb targetWeb, ILog log)
            : base(siteCollection, targetWeb, new NoLog())
        {

        }

        #endregion

        #region Create / Update Content Type

        /// <summary>
        /// Create a new content type in the current site collection or updates an existing one.
        /// 
        /// As we cant set the id of a newly created content type in code in the current version
        /// of sharepoint you will need to create a content type with a known
        /// id in the caml of your feature if thats what you require
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        internal SPContentType UpdateContentType(ContentType contentType)
        {
            SPContentType spContentType = null;

            try
            {
                Log.WriteToLog("Starting to add/update ContentType " + contentType.Name);

                if (ContentTypeExists(contentType))
                {
                    spContentType = TargetWeb.AvailableContentTypes[contentType.Id];

                    if (contentType.DoNotUpdateIfPresent) return spContentType;

                    //// Get the SPContentType object and delete the copy that is in the content type collection.
                    //Log.WriteToLog(String.Format(" ContentType {0} already exists. Deleting", contentType.Name));

                    //TargetWeb.AvailableContentTypes.Delete(contentType.Id);
                }
                else
                {
                    // Create a new content type

                    // Content Types cannot be created from scratch!  They must inherit from an existing type.
                    // * For Content Types that are used in Document Libraries, the parent must be a type that ultimately
                    //   inherits from the "Document" Content Type.
                    // * For Content Types that are used in lists, the parent must be a type that ultimately inherits from the "Item"
                    //   Content Type.

                    SPContentType parentContentType;


                    Log.WriteToLog(" Attempting to create new ContentType " + contentType.Name);

                    // This may need to be amended later to allow the parent type to be set to a type that has inherited from one of the base types.
                    if (contentType.BaseType == ContentBaseType.Document)
                    {
                        parentContentType = TargetWeb.AvailableContentTypes["Document"];
                    }
                    else
                    {
                        parentContentType = TargetWeb.AvailableContentTypes["Item"];
                    }
                    Log.WriteToLog(" Base ContentType for " + contentType.Name + " is " + parentContentType.Name);
                    spContentType = new SPContentType(parentContentType, TargetWeb.ContentTypes, contentType.Name);
                }

                spContentType.Name = contentType.Name;
                spContentType.Description = contentType.Description;

                // Loop through the list of SiteColumn objects in contentType and add fieldlinks to them in
                // the spContentType.
                // - provisioning the SiteColumns if they do not already exist.
                ProvisionFieldLinks(contentType, spContentType);

                // Add any required event handlers
                ProvisionEventHandlers(contentType, spContentType);

                // Add any workflow associations
                ProvisionWorkflows(contentType, spContentType);

                TargetWeb.ContentTypes.Add(spContentType);
                TargetWeb.Update();
                Log.WriteToLog("ContentType " + contentType.Name + "has been added.");

                }
                catch (Exception e)
                {
                    Log.WriteToLog("Unexpected error creating ContentType " + contentType.Name, e);
                    throw;
                }
                return spContentType;
        }

        private void ProvisionWorkflows(ContentType contentType, SPContentType spContentType)
        {
            throw new NotImplementedException();
        }

        private void ProvisionEventHandlers(ContentType contentType, SPContentType spContentType)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region Provision Content Types

        public void ProvisionContentTypes(List<ContentType> contentTypes)
        {
            foreach (ContentType contentType in contentTypes)
            {
                UpdateContentType(contentType);
            }
        }

        #endregion

        #region Fields

        /// <summary>
        /// Add fields to a content type.
        /// Any fields that already exist are added as FieldLinks.
        /// Any that do not currently exist are created as SiteColumns before being added as FieldLinks.
        /// </summary>
        /// <param name="contentType">This is the abstract ContentType object, which contains the names and types of the fields</param>
        /// <param name="spContentType">This is the SPContentType object being provisioned - the target object that will contain the actual fields</param>
        public void ProvisionFieldLinks(ContentType contentType, SPContentType spContentType)
        {
            // Instansiate the IDSiteColumnHelper to add any SiteColumns that do not already exist.
            IDSiteColumnHelper _idSiteColumnHelper = new IDSiteColumnHelper(SiteCollection, TargetWeb, Log);

            // The arguments/parameters passed to this method are passed as reference variables by default.
            // Therefore, the changes made to them within this method are applied to the original objects.

            // Loop through the fields within the contentType object and create SiteColumns for any that 
            // do not already exist.
            Log.WriteToLog("Adding ContentType fields - Start.");
            Log.WriteToLog(" Number of fields: " + contentType.SiteColumns.Count.ToString());
            int errorCount = 0;
            foreach (Field column in contentType.SiteColumns)
            {
                SPField field = TargetWeb.AvailableFields[column.Name];
                try
                {
                    if (field == null) // This SiteColumn *does not* already exist.
                    {
                        Log.WriteToLog("  Creating new SiteColumn " + column.Name);

                        // Create the SiteColumn to link to.
                        _idSiteColumnHelper.ProvisionSiteColumn(column);
                        
                        // now, get the newly-created field.
                        field = TargetWeb.AvailableFields[column.Name];
                    }

                    // At this point the SiteColumn (field) either already existed, or we have created it.
                    // Either way, it is now available for us to add to the ContentType.
                    Log.WriteToLog("  Adding the SiteColumn " + column.Name + " to ContentType " + contentType.Name);

                    // Add the SiteColumn to the ContentType as a FieldLink.
                    spContentType.FieldLinks.Add(new SPFieldLink(field));
                    spContentType.Update(false);
                }
                catch (Exception ex)
                {
                    Log.WriteToLog(" Error adding " + column.Name + " to ContentType " + contentType.Name, ex);
                    errorCount++;
                }
            }

            Log.WriteToLog("Adding ContentType fields - Completed with " + errorCount.ToString() + " Errors.");

        }

        #endregion

        #region Content Type Exists

        public bool ContentTypeExists(ContentType contentType)
        {
            bool exists = false;

            foreach (SPContentType spContentType in TargetWeb.AvailableContentTypes)
            {
                if (spContentType.Name == contentType.Name)
                {
                    exists = true;
                    break;
                }
            }

            return exists;
        }

        #endregion

        #region Get Content Type

        #region Test code to be removed

        internal SPContentType GetContentType()
        {
            SPContentType contentType = null;

            foreach (SPContentType spContentType in SiteCollection.RootWeb.ContentTypes)
            {
                if (spContentType.Name == "StudyCreation1")
                {
                    contentType = spContentType;
                    break;
                }
            }

            return contentType;
        }

        #endregion

        
        public SPContentType GetContentType(SPContentTypeId id)
        {
            return TargetWeb.AvailableContentTypes[id];
        }

        #endregion
    }
}
